﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WgFrame.Utils
{
    public class GBitConverter
    {
        public static byte[] GetBytes(bool data)
        {
            byte[] bytes = new byte[1];
            bytes[0] = (byte)(data ? 1 : 0);
            return bytes;
        }

        public static byte[] GetBytes(short data)
        {
            byte[] bytes = new byte[2];
            if (isLittleEndian())
            {
                bytes[0] = (byte)(data & 0xff);
                bytes[1] = (byte)((data & 0xff00) >> 8);
            }
            else
            {
                bytes[1] = (byte)(data & 0xff);
                bytes[0] = (byte)((data & 0xff00) >> 8);
            }
            return bytes;
        }

        public static byte[] GetBytes(char data)
        {
            byte[] bytes = new byte[2];
            if (isLittleEndian())
            {
                bytes[0] = (byte)(data);
                bytes[1] = (byte)(data >> 8);
            }
            else
            {
                bytes[1] = (byte)(data);
                bytes[0] = (byte)(data >> 8);
            }
            return bytes;
        }

        public static byte[] GetBytes(int data)
        {
            byte[] bytes = new byte[4];
            if (isLittleEndian())
            {
                bytes[0] = (byte)(data & 0xff);
                bytes[1] = (byte)((data & 0xff00) >> 8);
                bytes[2] = (byte)((data & 0xff0000) >> 16);
                bytes[3] = (byte)((data & 0xff000000) >> 24);
            }
            else
            {
                bytes[3] = (byte)(data & 0xff);
                bytes[2] = (byte)((data & 0xff00) >> 8);
                bytes[1] = (byte)((data & 0xff0000) >> 16);
                bytes[0] = (byte)((data & 0xff000000) >> 24);
            }
            return bytes;
        }

        public static byte[] GetBytes(long data)
        {
            byte[] bytes = new byte[8];
            if (isLittleEndian())
            {
                bytes[0] = (byte)(data & 0xff);
                bytes[1] = (byte)((data >> 8) & 0xff);
                bytes[2] = (byte)((data >> 16) & 0xff);
                bytes[3] = (byte)((data >> 24) & 0xff);
                bytes[4] = (byte)((data >> 32) & 0xff);
                bytes[5] = (byte)((data >> 40) & 0xff);
                bytes[6] = (byte)((data >> 48) & 0xff);
                bytes[7] = (byte)((data >> 56) & 0xff);
            }
            else
            {
                bytes[7] = (byte)(data & 0xff);
                bytes[6] = (byte)((data >> 8) & 0xff);
                bytes[5] = (byte)((data >> 16) & 0xff);
                bytes[4] = (byte)((data >> 24) & 0xff);
                bytes[3] = (byte)((data >> 32) & 0xff);
                bytes[2] = (byte)((data >> 40) & 0xff);
                bytes[1] = (byte)((data >> 48) & 0xff);
                bytes[0] = (byte)((data >> 56) & 0xff);
            }
            return bytes;
        }

        public static byte[] GetBytes(float data)
        {
            byte[] bytes = BitConverter.GetBytes(data);
            if (!isLittleEndian()) 
            {
                Array.Reverse(bytes);
            }
            return bytes;
        }

        public static byte[] GetBytes(double data)
        {
            byte[] bytes = BitConverter.GetBytes(data);
            if (!isLittleEndian())
            {
                Array.Reverse(bytes);
            }
            return bytes;
        }

        public static byte[] GetBytes(string data)
        {
            return Encoding.UTF8.GetBytes(data);
        }

        public static bool ToBoolean(byte[] bytes)
        {
            return bytes[0] != 0;
        }

        public static bool ToBoolean(byte[] bytes, int startIndex)
        {
            return ToBoolean(CopyFrom(bytes, startIndex, 1));
        }

        public static short ToShort(byte[] bytes)
        {
            if (isLittleEndian())
            {
                return (short)((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
            }
            else
            {
                return (short)((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
            }
        }

        public static short ToShort(byte[] bytes, int startIndex)
        {
            return ToShort(CopyFrom(bytes, startIndex, 2));
        }

        public static char ToChar(byte[] bytes)
        {
            if (isLittleEndian())
            {
                return (char)((0xff & bytes[0]) | (0xff00 & (bytes[1] << 8)));
            }
            else
            {
                return (char)((0xff & bytes[1]) | (0xff00 & (bytes[0] << 8)));
            }
        }

        public static char ToChar(byte[] bytes, int startIndex)
        {
            return ToChar(CopyFrom(bytes, startIndex, 2));
        }

        public static int ToInt(byte[] bytes)
        {
            if (isLittleEndian())
            {
                return (((bytes[0] | (bytes[1] << 8)) | (bytes[2] << 0x10)) | bytes[3] << 0x18);
            }
            else
            {
                return ((((bytes[0] << 0x18) | (bytes[1] << 0x10)) | (bytes[2] << 8)) | bytes[3]);
            }
        }

        public static int ToInt(byte[] bytes, int startIndex)
        {
            return ToInt(CopyFrom(bytes, startIndex, 4));
        }

        public static long ToLong(byte[] bytes)
        {
            if (isLittleEndian())
            {
                return ((((((((long)bytes[0]
                    | ((long)bytes[1] << 8))
                    | ((long)bytes[2] << 0x10))
                    | ((long)bytes[3] << 0x18))
                    | ((long)bytes[4] << 0x20))
                    | ((long)bytes[5] << 40))
                    | ((long)bytes[6] << 0x30))
                    | (long)bytes[7] << 0x38);
            }
            else
            {
                return (((((((((long)bytes[0] << 0x38) 
                    | ((long)bytes[1] << 0x30)) 
                    | ((long)bytes[2] << 40)) 
                    | ((long)bytes[3] << 0x20)) 
                    | ((long)bytes[4] << 0x18)) 
                    | ((long)bytes[5] << 0x10)) 
                    | ((long)bytes[6] << 8)) 
                    | (long)bytes[7]);
           
            }
        }

        public static long ToLong(byte[] bytes, int startIndex)
        {
            return ToLong(CopyFrom(bytes, startIndex, 8));
        }

        public static float ToFloat(byte[] bytes)
        {
            if (!isLittleEndian())
            {
                Array.Reverse(bytes);
            }
            return BitConverter.ToSingle(bytes, 0);
        }

        public static float ToFloat(byte[] bytes, int startIndex)
        {
            return ToFloat(CopyFrom(bytes, startIndex, 4));
        }

        public static double ToDouble(byte[] bytes)
        {
            if (!isLittleEndian())
            {
                Array.Reverse(bytes);
            }
            return BitConverter.ToDouble(bytes, 0);
        }

        public static double ToDouble(byte[] bytes, int startIndex)
        {
            return ToDouble(CopyFrom(bytes, startIndex, 8));
        }

        public static String ToString(byte[] bytes)
        {
            return Encoding.UTF8.GetString(bytes);
        }

        public static String ToString(byte[] bytes, int startIndex, int count)
        {
            return Encoding.UTF8.GetString(bytes, startIndex, count);
        }

        public static String ToHexString(byte[] bytes)
        {
            if (bytes == null)
            {
                return "null";
            }
            int iMax = bytes.Length - 1;
            if (iMax == -1)
            {
                return "[]";
            }
            StringBuilder b = new StringBuilder();
            b.Append('[');
            for (int i = 0; ; i++)
            {
                b.Append(String.Format("%02x", bytes[i] & 0xFF));
                if (i == iMax)
                {
                    return b.Append(']').ToString();
                }
                b.Append(", ");
            }
        }


        private static byte[] CopyFrom(byte[] src, int off, int len)
        {
            byte[] bits = new byte[len];
            Array.Copy(src, off, bits, 0, len);
            return bits;
        }

        private static bool isLittleEndian()
        {
            return true;
        }
    }
}
